
parameter int WID_DCU_RIB       = n2w(NUM_DCU_RIB),
              WID_DCU_DIB       = n2w(NUM_DCU_DIB),
              WID_DCU_EWB       = n2w(NUM_DCU_EWB),
              WID_DCU_SDB       = n2w(NUM_DCU_SDB),
              WID_DCU_RDB       = n2w(NUM_DCU_RDB),
              WID_DCU_ASB       = n2w(NUM_DCU_ASB),
              WID_DCU_RWB       = n2w(NUM_DCU_RWB),
              WID_DCU_ERB       = n2w(NUM_DCU_ERB),
              WID_DCU_ORB       = n2w(NUM_DCU_ORB),
              WID_DCU_RRB       = n2w(NUM_DCU_RRB),
              WID_DCU_ERIB      = n2w(NUM_DCU_ERIB),
              WID_DCU_EDIB      = n2w(NUM_DCU_EDIB),
              WID_DCU_SID       = max2(WID_DCU_ERIB, max2(WID_DCU_SDB, WID_DCU_EDIB));

typedef logic[WID_DCU_SDB - 1:0] dcsdb_t;
typedef logic[WID_DCU_RDB - 1:0] dcrdb_t;
typedef logic[WID_DCU_RIB - 1:0] dcrib_t;
typedef logic[WID_DCU_DIB - 1:0] dcdib_t;
typedef logic[WID_DCU_EWB - 1:0] dcewb_t;
typedef logic[WID_DCU_RWB - 1:0] dcrwb_t;
typedef logic[WID_DCU_ERB - 1:0] dcerb_t;
typedef logic[WID_DCU_ASB - 1:0] dcasb_t;
typedef logic[WID_DCU_SID - 1:0] dcsid_t;
typedef logic[WID_DCU_RRB - 1:0] dcrrb_t;
typedef logic[WID_DCU_ORB - 1:0] dcorb_t;
typedef logic[WID_DCU_ERIB - 1:0] dcerib_t;
typedef logic[WID_DCU_EDIB - 1:0] dcedib_t;
typedef logic[2:0] ccnt_t;

typedef enum logic[2:0] {
  ct_nor = 3'd4,    ct_lck = 3'd7
}ccnt_typ_t;

typedef enum logic[1:0] {
  ch_nor,   ch_lck,   ch_cs,    ch_na
}ch_typ_t;

typedef enum logic[2:0] {
  cs_uc,  cs_ud,  cs_sc,  cs_sd,  cs_i
}cache_state_t;

typedef enum logic[2:0]{
  cr_inv, cr_shared,  cr_clean, cr_nshared, cr_unique
} cache_require_e;

typedef enum logic[3:0]{
  mt_dvnb,  mt_dvb,   mt_ncnb,  mt_ncb,
  mt_wtra,  mt_wtrwa, mt_wbra,  mt_wbrwa,
  mt_sm
} dcu_mem_typ_e;

///  biu2dcu:
///  ia_typ   | hasData |  meaning:
///-----------+---------+----------------------------------------
///  at_rd    |    0    |  at_snp response
///  at_rd    |    1    |  at_rd response
///  at_wr    |    0    |  at_wr response
///  at_wr    |    1    |  N/A
///  at_sm    |    0    |  ext sm read
///  at_sm    |    1    |  ext sm write
///  at_snp   |    0    |  normal snoop request
///  at_snp   |    1    |  snoop request with cache data

/// dcu2biu:
///  ia_typ   |  meaning:
///-----------+---------+----------------------------------------
///  at_rd    |  read request
///  at_wr    |  write request
///  at_sm    |  N/A
///  at_snp   |  like a at_rd but require no data

typedef enum logic[1:0]{
  at_rd,   at_wr,   at_sm,    at_snp
} dcu_acc_typ_e;

typedef struct {
  logic lock;
  cache_require_e cr;
  dcu_acc_typ_e at;
  dcu_mem_typ_e mt;
  cache_state_t cs;  ///current cache state
  dcerb_t id, cid;
  logic[1:0] prot, domain, ch;
  padr_t adr;
  ///read data strb
  logic[NUM_DCHE_CL - 1:0][NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] strb;
} dcu_ar_inf_s;

parameter dcu_ar_inf_s dcu_ar_inf_def ='{
  mt     : mt_dvnb,
  cr     : cr_inv,
  cs     : cs_i,
  at     : at_rd,
  default : '0
};

typedef enum logic[1:0]{
  rt_ok,    rt_exok,    rt_slverr,   rt_err
} resp_typ_e;

typedef struct {
  dcu_acc_typ_e at;
  logic hasData;
  cache_state_t cs, ns;  ///current cache state, next state
  dcerb_t id;
  resp_typ_e resp;
} dcu_ir_inf_s;

parameter dcu_ir_inf_s dcu_ir_inf_def ='{
  at      : at_rd,
  ns      : cs_i,
  cs      : cs_i,
  resp    : rt_ok,
  default : '0
};

typedef struct {
  logic[NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] strb; 
  byt[NUM_SMEM_BK - 1:0][WORD_BITS - 1] data;
} dcu_od_inf_s;

parameter dcu_od_inf_s dcu_od_inf_def ='{
  default : '0
};

typedef struct packed{
  logic id, ia;
} dcu2biu_rsp_s;

typedef struct packed{
  logic ar, ir, od, odlast;
  cl_t odcl;
} dcu2biu_req_s;

typedef struct {
  dcu2biu_rsp_s rsp;
  dcu2biu_req_s req;

  dcu_ar_inf_s ar;
  dcu_od_inf_s od;
  dcu_ir_inf_s ir;
} dcu2biu_s;

parameter dcu2biu_s dcu2biu_def = '{
  ar      : dcu_ar_inf_def,
///  aw      : dcu_aw_inf_def,
  ir      : dcu_ir_inf_def,
  od      : dcu_od_inf_def,
///  idcs    : cs_i,
  default : '0
};

typedef struct {
  ///input data strb or state
  logic[NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] strb;
  byt[NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] data;
} dcu_id_inf_s;

parameter dcu_id_inf_s dcu_id_inf_def ='{
  default : '0
};

typedef struct {
  cache_require_e cr;
  dcu_acc_typ_e at;
  padr_t adr;
  dcerb_t id;
  logic lck;
///  tid_t lckid;
  cache_state_t cs;
  logic hasData;
  resp_typ_e resp;
  ///read data strb
  logic[NUM_DCHE_CL - 1:0][NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] strb;
} dcu_ia_inf_s;

parameter dcu_ia_inf_s dcu_ia_inf_def ='{
  cs      : cs_i,
  at      : at_rd,
  cr      : cr_inv,
  resp    : rt_ok,
  default : '0
};

typedef struct packed {
  logic id, idlast;
  cl_t idcl;
  logic ia; ///input addr req
} biu2dcu_req_s;

typedef struct packed {
  logic ar, ir, od;
} biu2dcu_rsp_s;

typedef struct {
  biu2dcu_req_s req;
  biu2dcu_rsp_s rsp;
  dcu_id_inf_s id;
  dcu_ia_inf_s ia;
} biu2dcu_s;

parameter biu2dcu_s biu2dcu_def = '{
  id      : dcu_id_inf_def,
  ia      : dcu_ia_inf_def,
  default : '0
};

typedef struct {
  vpn_t vpn;
  grpid_t gid;
} tlb_r_inf_s;

parameter tlb_r_inf_s tlb_r_inf_def = '{
  default : '0
};

typedef struct {
  logic req;
  tlb_r_inf_s r;
} dcu2tlb_s;

parameter dcu2tlb_s dcu2tlb_def = '{
  r       : tlb_r_inf_def,
  default : '0
};

typedef struct {
  logic wp, miss;
  pfn_t pfn;
  logic[1:0] prot, domain;
  dcu_mem_typ_e mt;
} tlb_i_inf_s;

parameter tlb_i_inf_s tlb_i_inf_def = '{
  mt      : mt_dvnb,
  default : '0
};

typedef struct {
  tlb_i_inf_s i;
} tlb2dcu_s;

parameter tlb2dcu_s tlb2dcu_def = '{
  i       : tlb_i_inf_def,
  default : '0
};

typedef logic[5:0] ahash_t;

function automatic ahash_t hashgen(input tag_t t, idx_t idx);
  ahash_t r;
  r = t;
  r &= idx;
  r &= t >> $bits(ahash_t);
  return r;
endfunction

typedef struct {
  lsu_ar_inf_s ar;
} dcu_rib_inf_s;

parameter dcu_rib_inf_s dcu_rib_inf_def = '{
  ar      : lsu_ar_inf_def,
  default : '0
};

typedef struct {
  lsu_sd_inf_s d;
  lsu_ar_inf_s ar;
  dcsdb_t sid;
} dcu_dib_inf_s;

parameter dcu_dib_inf_s dcu_dib_inf_def = '{
  d       : lsu_sd_inf_def,
  default : '0
};

typedef struct {
  lsu_ar_inf_s ar;
  tlb_i_inf_s tlb;
  lsu_sd_inf_s d;
  dcu_ar_inf_s oa;
  logic areq, flush;
  dcsdb_t sid;
  ahash_t ahash;
} dcu_erb_inf_s;

parameter dcu_erb_inf_s dcu_erb_inf_def = '{
  ar      : lsu_ar_inf_def,
  tlb     : tlb_i_inf_def,
  d       : lsu_sd_inf_def,
  oa      : dcu_ar_inf_def,
  default : '0
};

typedef struct {
  lsu_ar_inf_s ar;
  tlb_i_inf_s tlb;
  lsu_sd_inf_s d;
  dcsdb_t sid;
  padr_t padr;
  ahash_t ahash;
  dcerb_t cid;
  logic efw,  ///wait for erb free
        cew;  ///wait for erb on cid
} dcu_rwb_inf_s;

parameter dcu_rwb_inf_s dcu_rwb_inf_def = '{
  ar      : lsu_ar_inf_def,
  tlb     : tlb_i_inf_def,
  d       : lsu_sd_inf_def,
  default : '0
};

typedef struct {
  dcu_ia_inf_s a;
} dcu_erib_inf_s;

parameter dcu_erib_inf_s dcu_erib_inf_def = '{
  a       : dcu_ia_inf_def,
  default : '0
};

typedef struct {
  dcu_ia_inf_s a;
  dcu_id_inf_s d[NUM_DCHE_CL];
} dcu_edib_inf_s;

parameter dcu_edib_inf_s dcu_edib_inf_def = '{
  a       : dcu_ia_inf_def,
  d       : '{default : dcu_id_inf_def},
  default : '0
};

typedef struct {
  logic v, reCheck;
  dcerb_t cid;
  dcu_ia_inf_s ia;
} dcu_ewb_inf_s;

parameter dcu_ewb_inf_s dcu_ewb_inf_def = '{
  ia      : dcu_ia_inf_def,
  default : '0
};

typedef struct {
  logic ls;
  lsu_s_inf_s s; 
  dcrdb_t rid;
} dcu_rrb_inf_s;

parameter dcu_rrb_inf_s dcu_rrb_inf_def = '{
  s       : lsu_s_inf_def,
  default : '0
};

typedef struct {
  logic useAdr;
  logic rw;
  lsu_ar_inf_s ar;
  smadr_t adr;
  dcsid_t sid;
  dcrdb_t rid;
  dcorb_t oid;
} dcu_asb_inf_s;

parameter dcu_asb_inf_s dcu_asb_inf_def = '{
  ar      : lsu_ar_inf_def,
  default : '0
};

typedef enum logic[1:0] {
  dos_i,   dos_dep,   dos_rdy,    dos_asb
}dcu_oreq_state_t;

typedef struct {
  dcu_oreq_state_t st;
  lsu_ar_inf_s ar;
  logic rw,
        cr,   ///cache read to wbData
        clcwr,///cache load cache write
        clrwr,///cache load rdb write
        sm;   ///which sm adr to choose
  smadr_t adr;
  logic[NUM_DCU_ORB-1:0] orbw; ///dependency on orb
  dcsid_t sid;
  dcerb_t eid;
  dcu_acc_typ_e at;
} dcu_orb_inf_s;

parameter dcu_orb_inf_s dcu_orb_inf_def = '{
  at      : at_rd,
  st      : dos_i,
  ar      : lsu_ar_inf_def,
  default : '0
};

typedef struct packed{
  logic v, last;
  smadr_t adr;
  dcerb_t eid;
  logic [NUM_SMEM_BK-1:0][WORD_BYTES-1:0] rv;
} crp_t;

typedef struct packed{
  logic v, cwr, rwr, last, bp;
  dcedib_t edib;
  dcorb_t oid;
  dcrdb_t rid;
  logic [NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0][WORD_BYTES-1:0] rv;
  smadr_t[NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0] radr;
  smadr_t adr;
} clp_t;

typedef struct packed{
  logic v, start;
  dcsdb_t sid;
  dcerb_t eid;
} srp_t;

typedef struct {
  logic[NUM_DCU_SDB-1:0] sdbv;
  logic[NUM_DCU_RDB-1:0] rdbv;
  logic[NUM_DCU_ASB-1:0] asbv;
  dcu_asb_inf_s asb[NUM_DCU_ASB];
  dcu_orb_inf_s irOrb, erOrb, orb[NUM_DCU_ORB];
  logic[NUM_SMEM_BK-1:0] bkv, bkw;
  dcsid_t[NUM_SMEM_BK-1:0] bksid;
  asbc_t[NUM_SMEM_BK-1:0] bksasid;
  dcrdb_t[NUM_SMEM_BK-1:0] bkrid[2];
  asbc_t[NUM_SMEM_BK-1:0] bkrasid[2];
  dcasb_t[NUM_SMEM_BK-1:0] bkraid[2];
  smadr_t[NUM_SMEM_BK-1:0] dRadr, dWadr;
  logic [NUM_SMEM_BK-1:0][WORD_BYTES-1:0] dBe;
  
  logic irWr, erWr;
  
  ///sdb to rdb proc
  srp_t[1:0] srp;
  lsu_ar_inf_s srar;
  
  ///cache write / rdb write proc
  clp_t[2:0] clp;
  logic[NUM_DCHE_CL-1:0] clclv;
  
  ///cache read proc
  crp_t[2:0] crp;
  logic [NUM_DCHE_CL-1:0][NUM_SMEM_BK-1:0][WORD_BYTES-1:0] crStrb;
  logic[NUM_DCHE_CL-1:0] crclv;
  dcu_acc_typ_e crat;
  
  byt[NUM_DCHE_CL-1:0][NUM_SMEM_BK-1:0][WORD_BYTES-1:0] od;
  logic[NUM_DCHE_CL-1:0][NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] odStrb; 
  dcerb_t odEid;
  logic odv, odlast;
  cl_t odcl;
  logic[NUM_DCHE_CL-1:0] odclv;
  dcu_acc_typ_e odat;
  
  ///strb result used to compared to req strb to gen exp
  logic[NUM_DCU_ASB-1:0][NUM_ASB_CYC-1:0][NUM_SMEM_BK-1:0] rstrb;
} dcu_o_inf_s;

parameter dcu_o_inf_s dcu_o_inf_def = '{
  asb     : '{default : dcu_asb_inf_def},
  orb     : '{default : dcu_orb_inf_def },
  irOrb   : dcu_orb_inf_def,
  erOrb   : dcu_orb_inf_def,
  bkrid   : '{default : '0},
  bkrasid : '{default : '0},
  bkraid  : '{default : '0},
  odat    : at_rd,
  crat    : at_rd,
  srar    : lsu_ar_inf_def,
  default : '0
};

typedef struct packed{
  par_t par;
  idx_t idx;
} pidx_t;

typedef struct {
  dcu_rrb_inf_s tlbpRrb, oapRrb, erpRrb, irpRrb, rrb[NUM_DCU_RRB];
  logic tlbpWr, oapWr, erpWr, irpWr;
  dcrrb_t rrbwp, rrbrp;
  logic rrbf;
} dcu_inf_s;

parameter dcu_inf_s dcu_inf_def = '{
  tlbpRrb : dcu_rrb_inf_def,
  oapRrb  : dcu_rrb_inf_def,
  erpRrb  : dcu_rrb_inf_def,
  irpRrb  : dcu_rrb_inf_def,
  rrb     : '{default : dcu_rrb_inf_def},
  default : '0
};

typedef struct {  
  ///tlb tag process
  lsu_ar_inf_s ar;
  lsu_sd_inf_s d;
  tlb_i_inf_s tlb;
  dcsdb_t sid;
  dcerb_t cid;
  padr_t padr;
  ahash_t ahash;
  logic oc, ex, ls, v, hit;
  aso_t aso;
  cache_state_t cs;
  cache_require_e cr;
  lsu_exrsp_e code;
} dcu_irp_inf_s;

parameter dcu_irp_inf_s dcu_irp_inf_def = '{
  ar      : lsu_ar_inf_def,
  d       : lsu_sd_inf_def,
  tlb     : tlb_i_inf_def,
  cs      : cs_i,
  cr      : cr_unique,
  code    : exr_ok,
  default : '0
};

typedef struct {
  dcu_rib_inf_s rib[NUM_DCU_RIB];
  dcu_dib_inf_s dib[NUM_DCU_DIB];
  dcu_rwb_inf_s rwb[NUM_DCU_RWB];
  
  logic[NUM_DCU_RWB-1:0] rwbv, rwbrdy;
  
  logic ribf, dibf, dibrf, rrbf;
  dcrib_t ribrp, ribwp;
  dcdib_t dibrp, dibwp, dibrdy;  
  
  dcu_irp_inf_s tlbp, irp[3];
  logic tlbprdy;
} dcu_r_inf_s;

parameter dcu_r_inf_s dcu_r_inf_def = '{
  rib     : '{default : dcu_rib_inf_def},
  dib     : '{default : dcu_dib_inf_def},
  rwb     : '{default : dcu_rwb_inf_def},
  tlbp    : dcu_irp_inf_def,
  irp     : '{default : dcu_irp_inf_def},
  default : '0
};

typedef struct {  
  ///new ext process
  dcu_ia_inf_s ia;
  lsu_ar_inf_s ar;
  tlb_i_inf_s tlb;
  dcrdb_t rid;
  dcedib_t edib;
  dcerb_t cid;
  ahash_t ahash;
  logic v, start, rdbw, cwb, cfill, evict, iaWait;
  smadr_t adr;
  aso_t asoWr;
  padr_t padr, flushPadr;
  cache_state_t cs, csf;
  lsu_exrsp_e code;
  dcu_ir_inf_s ir;
} dcu_erp_inf_s;

parameter dcu_erp_inf_s dcu_erp_inf_def = '{
  ia      : dcu_ia_inf_def,
  ar      : lsu_ar_inf_def,
  tlb     : tlb_i_inf_def,
  cs      : cs_i,
  csf     : cs_i,
  ir      : dcu_ir_inf_def,
  code    : exr_ok,
  default : '0
};

typedef struct {
  dcu_edib_inf_s edib[NUM_DCU_EDIB];
  dcu_erib_inf_s erib[NUM_DCU_ERIB];
  dcu_ewb_inf_s  ewb[NUM_DCU_EWB];
  dcu_erb_inf_s  irErb, erb[NUM_DCU_ERB];
  
  logic[NUM_DCU_ERB-1:0] erbv;
  logic irWr;
  
  logic edibf, eribf, edibrf;
  dcedib_t edibrp, edibwp, edibrdy, edibprc;
  dcerib_t eribrp, eribwp;
  
  dcu_erp_inf_s erp[3];
  
  logic arReq;
  dcerib_t arEid;
} dcu_e_inf_s;

parameter dcu_e_inf_s dcu_e_inf_def = '{
  edib    : '{default : dcu_edib_inf_def},
  erib    : '{default : dcu_erib_inf_def},
  ewb     : '{default : dcu_ewb_inf_def},
  erb     : '{default : dcu_erb_inf_def},
  erp     : '{default : dcu_erp_inf_def},
  irErb   : dcu_erb_inf_def,
  default : '0
};

typedef struct packed{
  logic ex;
  logic[NUM_THREAD-1:0] id;
} lck_t;

typedef struct {
  cache_state_t[NUM_DCHE_ASO - 1:0] cstate[NUM_DCHE_ENT*NUM_SMEM_PAR];
  ccnt_t[NUM_DCHE_ASO - 1:0] cnt[NUM_DCHE_ENT*NUM_SMEM_PAR];
  lck_t[NUM_DCHE_ASO - 1:0] lck[NUM_DCHE_ENT*NUM_SMEM_PAR];
 
  logic irRd, irWr, irLckWr;
  pidx_t irRdIdx, irWrIdx;
  aso_t irWrAso;
  cache_state_t[NUM_DCHE_ASO - 1:0] irSt;
  cache_state_t irWrSt;
  ccnt_t[NUM_DCHE_ASO - 1:0] irCnt, irWrCnt;
  lck_t[NUM_DCHE_ASO - 1:0] irLck;
  lck_t irWrLck;
  
  logic erRd, erWr, erLckWr;
  pidx_t erRdIdx, erWrIdx;
  tag_t erWrTag;
  aso_t erWrAso;
  cache_state_t[NUM_DCHE_ASO - 1:0] erSt;
  cache_state_t erWrSt;
  ccnt_t[NUM_DCHE_ASO - 1:0] erCnt, erWrCnt;
  lck_t[NUM_DCHE_ASO - 1:0] erLck;
  lck_t erWrLck;
} dcu_c_inf_s;

parameter dcu_c_inf_s dcu_c_inf_def = '{
  cstate  : '{default : cs_i},
  cnt     : '{default : '0},
  lck     : '{default : '0},
  irSt    : '{default : cs_i},
  irWrSt  : cs_i,
  erSt    : '{default : cs_i},
  erWrSt  : cs_i,
  default : '0
};

typedef struct {
  byt[NUM_SMEM_BK-1:0][WORD_BYTES-1:0] bpData;
  byt[NUM_DCHE_CL-1:0][NUM_SMEM_BK-1:0][WORD_BYTES-1:0] stData, wbData;
  logic[NUM_DCHE_CL-1:0][NUM_SMEM_BK - 1:0][WORD_BITS - 1:0] wbStrb, stStrb;
  
  tag_t[NUM_DCHE_ASO-1:0] irTag, erTag;
  
  lsu2dcu_s lsu;
  tlb2dcu_s tlb;
  biu2dcu_s biu;
  dcu2lsu_s dcu2lsu;
  dcu2tlb_s dcu2tlb;
  dcu2biu_s dcu2biu;
} dcu_io_inf_s;

parameter dcu_io_inf_s dcu_io_inf_def = '{
  lsu     : lsu2dcu_def,
  tlb     : tlb2dcu_def,
  biu     : biu2dcu_def,
  dcu2lsu : dcu2lsu_def,
  dcu2tlb : dcu2tlb_def,
  dcu2biu : dcu2biu_def,
  default : '0
};
